<template>
	<view class="circle-progress" :class="size==='small'?'small':'big'">
		<!-- 有的不支持canvas-id属性，必须用id属性 -->
		<canvas class="canvas-bg" :canvas-id="canvasId" :id="canvasId" :style="{
				width: widthPx + 'px',
				height: widthPx + 'px'
			}"></canvas>
		<canvas class="canvas" :canvas-id="elId" :id="elId" :style="{
				width: widthPx + 'px',
				height: widthPx + 'px'
			}"></canvas>
		<slot></slot>
	</view>
</template>

<script>
	export default {
		name: 'circle-progress',
		props: {
			// 圆环进度百分比值
			percent: {
				type: [Number, String],
				default: 0,
				// 值在0到100之间
				validator: val => {
					return val >= 0 && val <= 100;
				}
			},
			size: {
				type: String,
				default: 'small'
			},
			// 圆环底色（灰色的圆环）
			inactiveColor: {
				type: String,
				default: '#393939'
			},
			// 圆环激活部分的颜色
			activeColor: {
				type: String,
				default: '#009dff'
			},
			// 圆环线条的宽度，单位rpx
			borderWidth: {
				type: [Number, String],
				default: 26
			},
			// 整个圆形的宽度，单位rpx
			width: {
				type: [Number, String],
				default: 170
			},
			// 整个圆环执行一圈的时间，单位ms
			duration: {
				type: [Number, String],
				default: 1500
			},
			progress_b_c: { //进度条渐变bottom颜色
				type: String,
				default: '#08246e'
			},
			progress_t_c: { //进度条渐变top颜色
				type: String,
				default: '#00c9a7'
			}
		},
		data() {
			return {
				canvasId: this.randomId(), //一个页面多个圆形进度
				elId: this.randomId(),
				widthPx: uni.upx2px(this.width), // 转成px后的整个组件的背景宽度
				borderWidthPx: uni.upx2px(this.borderWidth), // 转成px后的圆环的宽度
				startAngle: -Math.PI / 2, // canvas画圆的起始角度，默认为3点钟方向，定位到12点钟方向
				progressContext: null, // 活动圆的canvas上下文
				newPercent: 0, // 当动态修改进度值的时候，保存进度值的变化前后值，用于比较用
				oldPercent: 0 // 当动态修改进度值的时候，保存进度值的变化前后值，用于比较用
			};
		},
		watch: {
			percent(nVal, oVal = 0) {
				if (nVal > 100) nVal = 100;
				if (nVal < 0) oVal = 0;
				this.newPercent = nVal;
				this.oldPercent = oVal;
				setTimeout(() => {
					this.drawCircleByProgress(oVal);
				}, 50);
			}
		},
		created() {
			// 赋值，用于加载后第一个画圆使用
			this.newPercent = this.percent;
			this.oldPercent = 0;
		},

		mounted() {
			this.drawProgressBg();
			this.drawCircleByProgress(this.oldPercent);
		},
		methods: {
			//一个页面多个progress时ID需不同
			randomId() {
				return 'progressId' + parseInt(Math.random() * 1000000)
			},
			drawProgressBg() {
				let ctx = uni.createCanvasContext(this.canvasId, this);
				ctx.setLineWidth(this.borderWidthPx); // 设置圆环宽度
				ctx.setStrokeStyle(this.inactiveColor); // 线条颜色
				ctx.beginPath(); // 开始描绘路径
				let radius = this.widthPx / 2;
				ctx.arc(radius, radius, radius - this.borderWidthPx, 0, 2 * Math.PI, false);
				ctx.stroke(); // 对路径进行描绘
				ctx.draw();
			},
			drawCircleByProgress(progress) {
				let ctx = this.progressContext;
				if (!ctx) {
					ctx = uni.createCanvasContext(this.elId, this);
					this.progressContext = ctx;
				}
				// 进度条的渐变(中心x坐标-半径-边宽，中心Y坐标，中心x坐标+半径+边宽，中心Y坐标)
				let gradient = ctx.createLinearGradient(20, 80, 30, 0);
				gradient.addColorStop('0', this.progress_b_c);
				gradient.addColorStop('1.0', this.progress_t_c);
				// 表示进度的两端为圆形
				ctx.setLineCap('round');
				// 设置线条的宽度和颜色
				ctx.setLineWidth(this.borderWidthPx);
				ctx.setStrokeStyle(gradient);
				// 计算过渡时间
				let time = Math.floor(this.duration / 200);
				let endAngle = ((2 * Math.PI) / 100) * progress + this.startAngle;
				ctx.beginPath();
				// 半径为整个canvas宽度的一半
				let radius = this.widthPx / 2;
				ctx.arc(radius, radius, radius - this.borderWidthPx, this.startAngle, endAngle, false);
				ctx.stroke();
				ctx.draw();
				// 增大了百分比
				if (this.newPercent > this.oldPercent) {
					progress++;
					if (progress > this.newPercent) return;
				} else {
					// 减少百分比
					progress--;
					if (progress < this.newPercent) return;
				}
				setTimeout(() => {
					// 定时器，为了让进度条有动画效果
					this.drawCircleByProgress(progress);
				}, time);
			}
		}
	};
</script>

<style lang="scss" scoped>
	.small {
		width: 260rpx;
		height: 260rpx;
	}

	.big {
		width: 500rpx;
		height: 500rpx;
	}

	.circle-progress {
		position: relative;
		background-image: url(/static/index/icon-bg.png);
		background-repeat: no-repeat;
		background-size: 100% 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		text-align: center;
	}

	.canvas-bg {
		position: absolute;
	}

	.canvas {
		position: absolute;
	}
</style>
